using System;
using System.Text;
using System.Reflection;
using System.ServiceModel;
using System.Configuration;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.InteropServices;
using TDS = Tridion.ContentManager.Interop.TDS;
using COM = System.Runtime.InteropServices.ComTypes;
using TDSDefines = Tridion.ContentManager.Interop.TDSDefines;
using System.Xml;
using System.Data;
using System.Data.SqlClient;


namespace Tridion.Gateway
{
    public class Context
    {
        IContextManager tdse;
        
        public Context(String Identity)
        {
           tdse = ContextManager.CreateContext(Identity);
           Initialize();
        }

        public string GetVersion()
        {
            return tdse.Version;
        }

        public Component GetComponent(string ComponentId, string PublicationId, bool EditMode, int Version)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            Component component = new Component(tdse.GetComponent(ComponentId, publication, EditMode, Version), false);
            Facade.ReleaseComObject(publication);
            return component;
        }

        public ComponentTemplate GetComponentTemplate(string ComponentTemplateId, string PublicationId, bool EditMode, int Version)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            ComponentTemplate template = new ComponentTemplate(tdse.GetComponentTemplate(ComponentTemplateId, publication, EditMode, Version), false);
            Facade.ReleaseComObject(publication);
            return template;
        }

        public Schema[] GetDestinationProtocols()
        {
            TDS.Schemas array = tdse.GetDestinationProtocols();
            Schema[] schemas = Array.CreateInstance(typeof(Schema), array.Count) as Schema[];
            for (int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                schemas[i] = new Schema(array[i + 1],false);
            }

            Facade.ReleaseComObject(array);
            return schemas;
        }

        public string GetEnumerationValues(string enumerations)
        {
            return tdse.GetEnumerationValues(enumerations);
        }

        public Folder GetFolder(string FolderId, string PublicationId)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            Folder folder = new Folder(tdse.GetFolder(FolderId, publication), false);
            Facade.ReleaseComObject(publication);
            return folder;
        }

        public virtual StructureGroup GetStructureGroup(string StructureGroupId, string PublicationId)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            StructureGroup structuregroups = new StructureGroup(tdse.GetStructureGroup(StructureGroupId, publication), false);
            Facade.ReleaseComObject(publication);
            return structuregroups;
        }

        public Group[] GetGroups()
        {
            List<Group> groupList = new List<Group>();
            TDS.Groups groups = tdse.GetGroups();
            foreach (TDS.Group group in groups)
            {
                groupList.Add(new Group(group,false));
            }
            Facade.ReleaseComObject(groups);
            return groupList.ToArray();
        }

        public string GetListApprovalStatuses(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListApprovalStatuses(ColumnFilter);
        }

        public string GetListDestinationProtocols(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListDestinationProtocols(ColumnFilter);     
        }

        public string GetListDirectoryServices(ListRowFilter[] RowFilters)
        {
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            return tdse.GetListDirectoryServices(rowfilter);
        }

        public string GetListDirectoryServiceTestUsers(string DirectoryService, string SearchDN, TDSDefines.EnumDirectorySearchTypes SearchType)
        {
            return tdse.GetListDirectoryServiceTestUsers(DirectoryService, SearchDN, SearchType);
        }

        #region custom
        
        public Item[] GetPublicationItems(Publication Publication)
        {
            return Item.Parse(GetPublicationListItems(Publication.ID, TDSDefines.ListColumnFilter.XMLListExtended, new ListRowFilter[] { }));
        }

        public Item[] GetStructureGroupItems(StructureGroup StructureGroup)
        {
            return Item.Parse(GetStructureGroupListItems(StructureGroup.Publication.ID, StructureGroup.ID, TDSDefines.ListColumnFilter.XMLListExtended, new ListRowFilter[] { }));
        }

        public Item[] GetFolderItems(Folder Folder)
        {
           return Item.Parse(GetFolderListItems(Folder.Publication.ID, Folder.ID,TDSDefines.ListColumnFilter.XMLListExtended, new ListRowFilter[]{}));
        }

        #endregion

        public string GetListItems(TDSDefines.ListColumnFilter ColumnFilter, ListRowFilter[] RowFilters)
        {
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            string value = tdse.GetListItems(ColumnFilter, rowfilter);
            Facade.ReleaseComObject(rowfilter);
            return value;
        }

        public string GetPublicationListItems(String PublicationId, TDSDefines.ListColumnFilter ColumnFilter, ListRowFilter[] RowFilters)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            string value = publication.GetListItems(ColumnFilter, rowfilter);
            Facade.ReleaseComObject(rowfilter);
            Facade.ReleaseComObject(publication);
            return value;
        }

        public string GetStructureGroupListItems(String PublicationId, String StructureGroupId, TDSDefines.ListColumnFilter ColumnFilter, ListRowFilter[] RowFilters)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            TDS.StructureGroup structureGroup = tdse.GetStructureGroup(StructureGroupId, publication);
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            string value = structureGroup.GetListItems(ColumnFilter, rowfilter);
            Facade.ReleaseComObject(rowfilter);
            Facade.ReleaseComObject(publication);
            Facade.ReleaseComObject(structureGroup);
            return value;
        }

        public string GetFolderListItems(String PublicationId, String FolderId, TDSDefines.ListColumnFilter ColumnFilter, ListRowFilter[] RowFilters)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            TDS.Folder folder = tdse.GetFolder(FolderId, publication);
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            string value = folder.GetListItems(ColumnFilter, rowfilter);
            Facade.ReleaseComObject(folder);
            Facade.ReleaseComObject(rowfilter);
            Facade.ReleaseComObject(publication);
            return value;
        }
        
        public string GetListMultimediaTypes(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListTargetTypes(ColumnFilter);
        }

        public string GetListNonSystemUsers(TDSDefines.EnumNonSystemUserType UserType, string NameOfDomainOrDirectory)
        {
            return tdse.GetListNonSystemUsers(UserType, NameOfDomainOrDirectory);
        }

        public string GetListPublications(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListPublications(ColumnFilter);
        }

        public string GetListPublicationTargets(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListPublicationTargets(ColumnFilter);
        }

        public string GetListTargetTypes(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListTargetTypes(ColumnFilter);
        }

        public string GetListTemplateTypes(TDSDefines.ListColumnFilter ColumnFilter, ListRowFilter[] RowFilters)
        {
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            string value = tdse.GetListTemplateTypes(ColumnFilter, rowfilter);
            Facade.ReleaseComObject(rowfilter);
            return value;
        }

        public string GetListTrustees(TDSDefines.TrusteeType TrusteeTypes, TDSDefines.ListColumnFilter ColumnFilter, ListRowFilter[] RowFilters)
        {
            TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
            foreach (ListRowFilter filter in RowFilters)
            {
                rowfilter.SetCondition(filter.Name, filter.Value);
            }
            string value = tdse.GetListTrustees(TrusteeTypes, ColumnFilter, rowfilter);
            Facade.ReleaseComObject(rowfilter);
            return value;
        }

        public string GetListVirtualFolderTypes(TDSDefines.ListColumnFilter ColumnFilter)
        {
            return tdse.GetListVirtualFolderTypes(ColumnFilter);
        }

        public string GetLocalizedErrorXML(string ErrorXML, int LangID)
        {
            return tdse.GetLocalizedErrorXML(ErrorXML, LangID);
        }

        public MultimediaType[] GetMultimediaTypes()
        {
            TDS.MultimediaTypes array = tdse.GetMultimediaTypes();
            MultimediaType[] multimediaTypes = Array.CreateInstance(typeof(MultimediaType), array.Count) as MultimediaType[];
            for (int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                multimediaTypes[i] = new MultimediaType(array[i + 1], false);
            }
            Facade.ReleaseComObject(array);
            return multimediaTypes;
        }

        public Page GetPage(string PageId, string PublicationId, bool EditMode, int Version)
        { 
            TDS.Publication publication = GetTDSPublication(PublicationId);
            Page page = new Page(tdse.GetPage(PageId, publication, EditMode, Version), false);
            Facade.ReleaseComObject(publication);
            return page;
        }

        public PageTemplate GetPageTemplate(string PageTemplateId, string PublicationId, bool EditMode, int Version)
        { 
            TDS.Publication publication = GetTDSPublication(PublicationId);
            PageTemplate template = new PageTemplate(tdse.GetPageTemplate(PageTemplateId, publication, EditMode, Version), false);
            Facade.ReleaseComObject(publication);
            return template;
        }

        public Publication GetPublication(string PublicationId)
        {
            return new Publication(tdse.GetPublication(PublicationId), false);
        }

        public virtual Publication[] GetPublications()
        {
            TDS.Publications array = tdse.GetPublications() as TDS.Publications;
            Publication[] publications = Array.CreateInstance(typeof(Publication), array.Count) as Publication[];
            for (int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                publications[i] = new Publication(array.get_Item(i + 1), false);
            }
            Facade.ReleaseComObject(array);
            return publications;

            //Publication[] pubs = Array.CreateInstance(typeof(Publication), publications.Count) as Publication[];
            //publications.Values.CopyTo(pubs,0);
            //return pubs;
        }

        public virtual PublicationTarget GetPublicationTarget(string PubTargetId)
        { 
            return new PublicationTarget(tdse.GetPublicationTarget(PubTargetId),false);
        }

        public virtual PublicationTarget[] GetPublicationTargets()
        { 
            TDS.PublicationTargets array = tdse.GetPublicationTargets();
            PublicationTarget[] publicationTargets = Array.CreateInstance(typeof(PublicationTarget), array.Count) as PublicationTarget[];
            for(int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                publicationTargets[i] = new PublicationTarget(array[i + 1], false);
            }
            Facade.ReleaseComObject(array);
            return publicationTargets;
        }

        public virtual User[] GetUsers()
        {
            TDS.Users array = tdse.GetUsers();
            User[] users = Array.CreateInstance(typeof(User), array.Count) as User[];
            for (int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                users[i] = new User(array[i + 1], false);
            }
            Facade.ReleaseComObject(array);
            return users;
        }

        public virtual Schema[] GetVirtualFolderTypes()
        {
            TDS.Schemas array = tdse.GetVirtualFolderTypes();
            Schema[] schemas = Array.CreateInstance(typeof(Schema), array.Count) as Schema[];
            for (int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                schemas[i] = new Schema(array[i + 1], false);
            }
            Facade.ReleaseComObject(array);
            return schemas;
        }

        public void FlushCache(string ObjectOrUri)
        {
            tdse.FlushCache(ObjectOrUri);
        }

        public ListRowFilter CreateListRowFilter()
        {
            return new ListRowFilter(tdse.CreateListRowFilter(),false);
            
        }

        //public virtual Search GetSearch()
        //{
        //    //TDS.Search search tdse.GetSearch();;
        //    //search.SetSearchInstruction();
        //    //search.
        //}

        //[OperationContract]

        public virtual string GetSystemXSD(string NameOrNamespaceUri)
        {
            return tdse.GetSystemXSD(NameOrNamespaceUri);
        }

        public virtual TargetType GetTargetType(string TargetTypeId)
        {
            return new TargetType(tdse.GetTargetType(TargetTypeId), false);
        }

        public virtual TargetType[] GetTargetTypes()
        {
            TDS.TargetTypes array = tdse.GetTargetTypes();
            TargetType[] targets = Array.CreateInstance(typeof(TargetType), array.Count) as TargetType[];
            for(int i = 0; i < array.Count; i++)
            {
                //TODO:Verify
                targets[i] = new TargetType(array[i + 1], false);
            }
            Facade.ReleaseComObject(array);
            return targets;
        
        }
        
        public virtual PublishTransaction GetPublishTransaction(string PublishTransactionId)
        {
            return new PublishTransaction(tdse.GetPublishTransaction(PublishTransactionId), false);
        }
        
        public String GetObject(string Uri, string PublicationId, TDSDefines.XMLReadFilter Filter, bool ShallowCopy)
        {
            TDS.Publication publication = GetTDSPublication(PublicationId);
            object comObject = tdse.GetObject(Uri, TDSDefines.EnumOpenMode.OpenModeView, publication, Filter);
            Facade.ReleaseComObject(publication);
            object o = Facade.Create(comObject, ShallowCopy);
            Facade.ReleaseComObject(comObject);
            if (o != null)
            {
                Type t = o.GetType();
                string xml = String.Empty;
                DataContractSerializer dc = new DataContractSerializer(t);

                using (System.IO.MemoryStream mem = new System.IO.MemoryStream())
                {
                    using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(mem, null))
                    {
                        System.Xml.XmlDictionaryWriter dictionaryWriter = System.Xml.XmlDictionaryWriter.CreateDictionaryWriter(writer);
                        writer.WriteStartElement(t.Name);
                        dc.WriteObjectContent(dictionaryWriter, o);
                        writer.WriteEndElement();
                        writer.Flush();
                        mem.Flush();
                        mem.Position = 0;
                        using (System.IO.StreamReader sr = new System.IO.StreamReader(mem))
                        {
                            xml = sr.ReadToEnd();
                            dictionaryWriter.Close();
                            sr.Close();
                        }
                        writer.Close();
                    }
                    mem.Close();
                }
                return xml;
            }

            throw new Exception("Item not found");
        }

        
        public String GetXML(string Uri, TDSDefines.XMLReadFilter Filter)
        {
            return tdse.GetXML(Uri, Filter);
        }

        
        public String[] GetXMLForEach(string[] URIs, TDSDefines.XMLReadFilter filter)
        {
            List<String> list = new List<string>();
            Array.ForEach<String>(URIs,new Action<string>(delegate(string Uri){
                list.Add(GetXML(Uri, filter)); 
            }));
            return list.ToArray();
        }

        
        public string GetNewObject(TDSDefines.ItemType ItemType, String PublicationId, String Folder, String Title, String Schema, String Xml)
        {
            string tcmid = String.Empty;
            switch (ItemType)
            { 
                case TDSDefines.ItemType.ItemTypeComponent:
                    TDS.Component component = null;
                    TDS.Publication publication = GetTDSPublication(PublicationId);
                    TDS.Folder folder = tdse.GetObject(Folder, TDSDefines.EnumOpenMode.OpenModeView, null, TDSDefines.XMLReadFilter.XMLReadNull) as TDS.Folder;
                    TDS.Schema schema = tdse.GetObject(Schema, TDSDefines.EnumOpenMode.OpenModeView, publication, TDSDefines.XMLReadFilter.XMLReadNull) as TDS.Schema;

                    XmlNamespaceManager nm = new XmlNamespaceManager(new NameTable());
                    nm.AddNamespace("tcm", "http://www.tridion.com/ContentManager/5.0");
                    XmlDocument listOfItemsInFolder = new XmlDocument();
                    TDS.ListRowFilter rowfilter = tdse.CreateListRowFilter();
                    rowfilter.SetCondition("ItemType", TDSDefines.ItemType.ItemTypeComponent);
                    listOfItemsInFolder.LoadXml(folder.GetListItems(TDSDefines.ListColumnFilter.XMLListIDAndTitle, rowfilter));

                    if (listOfItemsInFolder.SelectSingleNode(String.Format("/tcm:ListItems/tcm:Item[@Title='{0}']", Title), nm) != null)
                    {
                        component = tdse.GetObject(listOfItemsInFolder.SelectSingleNode(String.Format("/tcm:ListItems/tcm:Item[@Title='{0}']/@ID",Title), nm).Value, TDSDefines.EnumOpenMode.OpenModeEdit, publication, TDSDefines.XMLReadFilter.XMLReadNull) as TDS.Component;
                    }
                    else
                    {
                        component = tdse.GetNewObject(TDSDefines.ItemType.ItemTypeComponent, folder, publication) as TDS.Component;
                        component.Schema = schema;
                        component.Title = Title;
                    }
                    component.UpdateXML(Xml);
                    component.Save(true);
                    tcmid = component.ID;

                    Facade.ReleaseComObject(folder);
                    Facade.ReleaseComObject(schema);
                    Facade.ReleaseComObject(component);
                    Facade.ReleaseComObject(rowfilter);
                    Facade.ReleaseComObject(publication);
                    

                    break;
                case TDSDefines.ItemType.ItemTypeComponentTemplate:
                case TDSDefines.ItemType.ItemTypeFolder:
                case TDSDefines.ItemType.ItemTypeGroup:
                case TDSDefines.ItemType.ItemTypeMultimediaType:
                case TDSDefines.ItemType.ItemTypePage:
                case TDSDefines.ItemType.ItemTypePageTemplate:
                case TDSDefines.ItemType.ItemTypePublication:
                case TDSDefines.ItemType.ItemTypePublicationTarget:
                case TDSDefines.ItemType.ItemTypeStructureGroup:
                case TDSDefines.ItemType.ItemTypeUser:
                case TDSDefines.ItemType.ItemTypeVirtualFolder:
                default:
                    throw new NotImplementedException(ItemType.ToString());
            }

            return tcmid;
        }

        
        public string ExecuteProc(string ProcedureName, Dictionary<string, string> Paramaters)
        {
            try
            {
                DataSet result = new DataSet();
                using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["TridionDatabase"].ToString()))
                {
                    using (SqlCommand cmd = new SqlCommand(ProcedureName, conn))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        foreach (KeyValuePair<string, string> item in Paramaters)
                        {
                            cmd.Parameters.Add(new SqlParameter(item.Key, item.Value));
                        }
                        if (conn.State != ConnectionState.Open)
                            conn.Open();
                        using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
                        {
                            adapter.Fill(result);
                        }
                        if (conn.State != ConnectionState.Closed)
                            conn.Close();
                    }
                }

                return result.GetXml().ToString();
            }
            catch
            {
                throw;
            }

        }


        private void Impersonate(string Identity)
        {
            tdse.Impersonate(Identity);
        }

        
        private void Initialize()
        {
            //TDS.Publications tdsPublications = tdse.GetPublications() as TDS.Publications;
            //publications = new Dictionary<String, Publication>();
            //foreach (TDS.Publication p in tdsPublications)
            //{
            //    publications.Add(p.ID,new Publication(p, false));
            //}
        }

        
        private TDS.Publication GetTDSPublication(String PublicationId)
        {
            TDS.Publication publication = null;
            if (!String.IsNullOrEmpty(PublicationId))
                publication = tdse.GetPublication(PublicationId);

            return publication;
        }

    }
}



//TDS.Logging GetLogging();
//public virtual TDS.WFE GetWFE();
//ManagementInfo GetManagementInfo();
//object CreateEmptyCollection(ItemType itemType);
//public virtual void SetListApprovalStatuses(string newListApprovalStatuses);
//object GetNewObject(ItemType itemType, object inOrgItem, object contextPublication);
